#include "persister.h"
#include "util.h"
#include <stdexcept>  // 用于异常处理
#include <sstream>    // 用于字符串流操作

namespace raftCore 
{
// 辅助函数：检查文件流状态并抛出异常（或记录错误）
template <typename Stream>
void checkStreamState(const Stream& stream, const std::string& operation) {
    if (stream.bad()) {
        throw std::runtime_error("File operation failed: " + operation + " (fatal error)");
    } else if (stream.fail()) {
        throw std::runtime_error("File operation failed: " + operation + " (non-fatal error)");
    }
}

// 优化：减少文件反复打开，通过内存缓存减少IO；增加错误处理
void Persister::Save(const std::string raftstate, const std::string snapshot) {
    std::lock_guard<std::mutex> lg(m_mutex);
    try {
        clearRaftStateAndSnapshot();    // 清空现有数据
        // 将raftstate和snapshot写入本地文件
        // 写入raftstate并检查状态
        m_raft_state_out_stream << raftstate;
        m_raft_state_out_stream.flush();  // 强制刷新，确保数据写入磁盘
        checkStreamState(m_raft_state_out_stream, "Save raftstate");

        // 写入snapshot并检查状态
        m_snapshot_out_stream << snapshot;
        m_snapshot_out_stream.flush();
        checkStreamState(m_snapshot_out_stream, "Save snapshot");
    }
    catch (const std::exception& e) {
        // 记录错误并尝试恢复（如重新打开文件）
        common::DPrintf("[Persister::Save] Error: %s, trying to recover...", e.what());
        recoverFileStreams();  // 恢复文件流
        throw;  // 向上层传递错误，让调用者处理
    }
}

// 优化：从内存缓存读取，避免文件IO；仅在缓存无效时读取文件
std::string Persister::ReadSnapshot() {
    std::lock_guard<std::mutex> lg(m_mutex);
    try {
        // 优先使用内存缓存，减少文件读取
        if (!m_snapshot.empty()) {
            return m_snapshot;
        }

        // 缓存无效时读取文件（仅一次IO）
        std::ifstream ifs(m_snapshot_file_name, std::ios_base::in | std::ios_base::binary);
        if (!ifs.is_open()) {
            throw std::runtime_error("Failed to open snapshot file for reading");
        }

        // 读取全部内容（避免使用>>，防止空格截断）
        std::stringstream ss;
        ss << ifs.rdbuf();  // 高效读取整个文件
        checkStreamState(ifs, "Read snapshot");
        m_snapshot = ss.str();  // 更新缓存
        return m_snapshot;
    }
    catch (const std::exception& e) {
        common::DPrintf("[Persister::ReadSnapshot] Error: %s", e.what());
        return "";  // 读取失败返回空，或根据业务逻辑处理
    }
}
  
void Persister::SaveRaftState(const std::string &data) {
    std::lock_guard<std::mutex> lg(m_mutex);
    try {
        clearRaftState();

        // 写入并刷新
        m_raft_state_out_stream << data;
        m_raft_state_out_stream.flush();
        checkStreamState(m_raft_state_out_stream, "SaveRaftState");

        // 更新内存缓存和大小
        m_raft_state = data;
        m_raft_state_size = data.size();
    } 
    catch (const std::exception& e) {
        common::DPrintf("[Persister::SaveRaftState] Error: %s, trying to recover...", e.what());
        recoverFileStreams();
        throw;
    }
}
  
long long Persister::RaftStateSize() {
    std::lock_guard<std::mutex> lg(m_mutex);
  
    return m_raft_state_size;
}
  
std::string Persister::ReadRaftState() {
    std::lock_guard<std::mutex> lg(m_mutex);
    try {
        if (!m_raft_state.empty()) {
            return m_raft_state;
        }

        std::ifstream ifs(m_raft_state_file_name, std::ios_base::in | std::ios_base::binary);
        if (!ifs.is_open()) {
            throw std::runtime_error("Failed to open raftstate file for reading");
        }

        std::stringstream ss;
        ss << ifs.rdbuf();
        checkStreamState(ifs, "Read raftstate");
        m_raft_state = ss.str();
        m_raft_state_size = m_raft_state.size();  // 更新大小缓存
        return m_raft_state;
    } 
    catch (const std::exception& e) {
        common::DPrintf("[Persister::ReadRaftState] Error: %s", e.what());
        return "";
    }
}
// 初始化文件流，检查打开状态
Persister::Persister(const int me)
: m_raft_state_file_name("raftstatePersist" + std::to_string(me) + ".txt"),
  m_snapshot_file_name("snapshotPersist" + std::to_string(me) + ".txt"),
  m_raft_state_size(0) {
    try {
        // 初始化文件流（以读写、截断模式打开，确保文件存在）
        m_raft_state_out_stream.open(m_raft_state_file_name, std::ios::out | std::ios::trunc | std::ios::binary);
        m_snapshot_out_stream.open(m_snapshot_file_name, std::ios::out | std::ios::trunc | std::ios::binary);

        // 检查文件流是否成功打开
        if (!m_raft_state_out_stream.is_open()) {
            throw std::runtime_error("Failed to open raftstate file: " + m_raft_state_file_name);
        }
        if (!m_snapshot_out_stream.is_open()) {
            throw std::runtime_error("Failed to open snapshot file: " + m_snapshot_file_name);
        }

        // 初始加载数据到内存缓存
        m_raft_state = ReadRaftState();
        m_snapshot = ReadSnapshot();
    } 
    catch (const std::exception& e) {
        common::DPrintf("[Persister::Persister] Init failed: %s", e.what());
        // 初始化失败可考虑终止程序或降级为内存模式（根据业务容忍度）
        throw;
    }
}
  
Persister::~Persister() {
    if (m_raft_state_out_stream.is_open()) {
        m_raft_state_out_stream.flush();
        m_raft_state_out_stream.close();
    }
    if (m_snapshot_out_stream.is_open()) {
        m_snapshot_out_stream.flush();
        m_snapshot_out_stream.close();
    }
}

// 清除Raft状态：保持流打开，仅截断内容
void Persister::clearRaftState() {
    if (m_raft_state_out_stream.is_open()) {
        m_raft_state_out_stream.close();
    }
    // 重新打开并截断（保持流打开状态，避免反复open/close）
    m_raft_state_out_stream.open(m_raft_state_file_name, std::ios::out | std::ios::trunc | std::ios::binary);
    if (!m_raft_state_out_stream.is_open()) {
        throw std::runtime_error("Failed to clear raftstate file");
    }
    m_raft_state.clear();  // 清空内存缓存
    m_raft_state_size = 0;
}

// 清除快照：同上，保持流打开
void Persister::clearSnapshot() {
    if (m_snapshot_out_stream.is_open()) {
        m_snapshot_out_stream.close();
    }
    m_snapshot_out_stream.open(m_snapshot_file_name, std::ios::out | std::ios::trunc | std::ios::binary);
    if (!m_snapshot_out_stream.is_open()) {
        throw std::runtime_error("Failed to clear snapshot file");
    }
    m_snapshot.clear();  // 清空内存缓存
}
  
void Persister::clearRaftStateAndSnapshot() {
    clearRaftState();
    clearSnapshot();
}

// 新增：文件流恢复函数（当流异常时尝试重新打开）
void Persister::recoverFileStreams() {
    // 恢复raftstate流
    if (!m_raft_state_out_stream.is_open() || m_raft_state_out_stream.fail()) {
        m_raft_state_out_stream.close();
        m_raft_state_out_stream.open(m_raft_state_file_name, std::ios::out | std::ios::app | std::ios::binary);
    }
    // 恢复snapshot流
    if (!m_snapshot_out_stream.is_open() || m_snapshot_out_stream.fail()) {
        m_snapshot_out_stream.close();
        m_snapshot_out_stream.open(m_snapshot_file_name, std::ios::out | std::ios::app | std::ios::binary);
    }
}

}   // namespace raftCore